<?php

// 微信常量
define('template_message_max_num', 25);     // 微信公众号允许设置的最大模板消息数量
define('template_message_max_industry_num', 2);     // 微信公众号允许设置的最大模板消息行业数量

/**
 * nmp后台模板消息管理
 * Class TemplateMessageAction
 * @author lilei<LL_strive@163.com> 2017-05-27
 */
class TemplateMessageAction extends Action {

    /**
     * 初始化方法
     */
    public function _initialize()
    {
        // 要求登录
        $this->retVal = Session::init();
        if (!$this->retVal) {
            Output::instance()->resultCode(code_access_denied);
            exit;
        }

        // 公共数据
        $this->cid = Session::$user["customerId"];
        Session::switchCustomer(0);
        $this->moduleTemplateInfoModel = D('module_template_info');
        $this->customerModuleModel     = D('customer_module_group');
        Session::switchCustomer($this->cid);
        $this->templateMessageModel    = D('template_messages');
    }

    /**
     * 普通用户登录获得自己的模板消息配置情况
     * 参照/Mall/gettemplatemsgList, 但这里由于它直接向页面输出, 故不在重构调用它
     *
     * @param int $start    开始便宜量
     * @param int $limit    查询数量
     * @param null $keyword 关键字查询
     */
    public function getTemplateMessages($start = 0, $limit = 10, $keyword = null)
    {
        $where = '';
        if (!empty($keyword)) {  // 进行关键字搜索, 短编号 或 名称
            $where = 'tm.name like "%' . $keyword . '%" OR mti.tmNo like "%'. $keyword . '%"';
        }

        $templateMessages = $this->templateMessageModel
            ->alias('tm')
            ->join('left join (select * from wx_module_template_info group by `type`) mti ON tm.status = mti.type')
            ->where($where)
            ->field('tm.id, tm.templateId, tm.name, mti.tmNo')
            ->limit($start, $limit)
            ->order('tm.id desc')
            ->select();

        if ($templateMessages) {    // 查询正常, 得到模板数据
            $templateMessages_count = $this->templateMessageModel
                ->alias('tm')
                ->join('left join (select * from wx_module_template_info group by `type`) mti ON tm.status = mti.type')
                ->where($where)
                ->count();
            Output::instance()->objArray($templateMessages, $templateMessages_count);
        } else {
            Output::instance()->resultCode(code_sql_error);
        }
    }

    /**
     * 超管给用户开通该模块时, 将模板消息添加到模板库中
     * !! 超级管理员才有权限 !!
     *
     * @param string $module       开启哪个模块
     * @param int    $user_cid     为哪个用户开启(这个用户的cid)
     */
    public function configModuleTemplate($module, $user_cid)
    {
        /** 0. 判断是不是超级管理员 */
        $isAdmin = Session::isAdmin();
        if (!$isAdmin) {
            Output::instance()->resultCode(code_user_priv_invalid);
            exit();
        }

        /** 1. 根据module拿到开通这个模块需要添加的模板信息 */
        $moduleTemplateInfoWhere = [
            'module'    => $module,
            'deleted'   => 0
        ];
        $moduleTemplateInfo = $this->moduleTemplateInfoModel->where($moduleTemplateInfoWhere)->select();

        $moduleTemplateInfo = isset($moduleTemplateInfo) ? $moduleTemplateInfo : [];
        /** 2. 遍历需要添加的模板消息, 并与微信公众号已有模板消息作判断 */
        $result = $this->addTemplate($moduleTemplateInfo, $user_cid);
        return $result;
    }

    /**
     * 超管关闭某个用户某个模块时, 将相应模板消息做移除(我们平台&公众号后台)
     * !! 超级管理员才有权限 !!
     *
     * @param string $module       关闭的哪个模块
     * @param int    $user_cid     关闭哪个用户(这个用户的cid)
     */
    public function cancelConfigModuleTemplate($module, $user_cid)
    {
        /** 0. 判断是不是超级管理员 */
        $isAdmin = Session::isAdmin();
        if (!$isAdmin) {
            Output::instance()->resultCode(code_user_priv_invalid);
            exit();
        }

        /** 1. 根据module拿到开通这个模块需要关闭的模板信息 */
        $moduleTemplateInfoWhere = [
            'module'    => $module,
            'deleted'   => 0
        ];
        $moduleTemplateInfo = $this->moduleTemplateInfoModel->where($moduleTemplateInfoWhere)->select();

        /** 2. 遍历需要关闭的模板信息, 并且同步删除公众后台的模板信息 */
        $result = $this->delTemplate($moduleTemplateInfo, $user_cid);
        return $result;
    }


    /**
     * 自动配置账号里所有模板消息
     * 配置templateId为NULL的所有项
     */
    public function autoConfigTemplate()
    {
        $templateMessageWhere['templateId'] = array(array('EXP','IS NULL'), array('eq', ''), 'or');
        $templateTypes = $this->templateMessageModel->where($templateMessageWhere)->getField('status', TRUE);

        $moduleTemplateInfo = null;
        if (isset($templateTypes)) {    // 只有存在待配置的模板消息的时候, 才进行配置筛选
            $moduleTemplateInfoWhere['type'] = isset($templateTypes) ? array('in', $templateTypes) : [];
            $moduleTemplateInfo = $this->moduleTemplateInfoModel->where($moduleTemplateInfoWhere)->group('type')->select();
        }

        $moduleTemplateInfo = isset($moduleTemplateInfo) ? $moduleTemplateInfo : [];
        $result = $this->addTemplate($moduleTemplateInfo, $this->cid);
        Output::instance()->resultCode($result['code'], $result['msg'] . $result['subMsg']);
    }

    /**
     * 单个配置账号里的模板消息
     * 根据点击的id单个配置
     */
    public function configTemplate($id)
    {
        $templateMessageWhere['id'] = array('eq', $id);
        $templateType = $this->templateMessageModel->where($templateMessageWhere)->getField('status');

        $moduleTemplateInfoWhere['type'] = array('eq', $templateType);
        $moduleTemplateInfo = $this->moduleTemplateInfoModel->where($moduleTemplateInfoWhere)->limit(1)->select();

        $moduleTemplateInfo = isset($moduleTemplateInfo) ? $moduleTemplateInfo : [];
        $result = $this->addTemplate($moduleTemplateInfo, $this->cid);
        Output::instance()->resultCode($result['code'], $result['msg'] . $result['subMsg']);
    }

    /**
     * 取消配置账号里的模板消息
     * 根据点击的id单个取消
     */
    public function cancelConfigTemplate($id)
    {
        $templateMessageWhere['id'] = array('eq', $id);
        $templateType = $this->templateMessageModel->where($templateMessageWhere)->getField('status');

        $moduleTemplateInfoWhere['type'] = array('eq', $templateType);
        $moduleTemplateInfo = $this->moduleTemplateInfoModel->where($moduleTemplateInfoWhere)->limit(1)->select();

        $result = $this->delTemplate($moduleTemplateInfo, $this->cid);
        Output::instance()->resultCode($result['code'], $result['msg'] . $result['subMsg']);
    }


    /*
    |--------------------------------------------------------------------------
    |                           以下为该类私有方法
    |--------------------------------------------------------------------------
    */

    /**
     * 与微信公众平台配置相管理处理,增加模板消息
     *
     * @param array $moduleTemplateInfo 需要配置的模板包含的模板信息
     * @param int   $user_cid           为哪个用户配置
     */
    protected function addTemplate($moduleTemplateInfo, $user_cid)
    {
        $code = 0;
        $msg  = (count($moduleTemplateInfo) > 0) ? '模板消息配置成功' : '没有待配置的模板';  // '没有待配置的模板' 这几个汉字在前端js里用作匹配, 不可随意更改, 需要改写要一致
        $subMsg = '';
        foreach ($moduleTemplateInfo as $moduleTemplate_index => $moduleTemplate) {

            /** 2.1 判断公众号模板消息已设置的行业是否符合要添加的模板消息 */
            // 获得公众号已设置的行业
            $industries = TemplateMessage::getIndustry($user_cid);
            $industries_count = isset($industries) ? count($industries) : 0;

            // 整理行业信息
            $arr_industry_id = [];
            foreach ($industries as $industry_index => $industry) {
                array_push($arr_industry_id, $industry->industry_id);
            }

            // 模板消息所属行业比较判断
            if (!in_array($moduleTemplate['industry_id'], $arr_industry_id)) { // 如果要添加的模板消息在现有行业中不存在
                if ($industries_count < template_message_max_industry_num) {  // 如果现有行业未设置到最大数量(2个), 则添加新行业
                    // 设置两个行业, 如果目前只设置了一个行业(或者说目前行业有空余可设置), 则将已设置的这个(或者说已设置的行业中的最后一个)作为已设置的第一个(或者说作为要设置的前一个)行业
                    $first_industry_id = $moduleTemplate['industry_id'];    // 设置默认第一个industry_id为要设置的id, 如果下面if不修改(这种情况实际不存在), 则两个行业设置一样
                    if ($industries_count == (template_message_max_industry_num - 1)) { // 2个 - 1个, 还空余一个可设置, 这也与上面 count < num 一致
                        $first_industry_id = $arr_industry_id[$industries_count - 1];   // 已设置的行业
                    }
                    $setIndustry_result = TemplateMessage::apiSetIndustry($user_cid, $first_industry_id, $moduleTemplate['industry_id']);
                    // todo: 设置行业错误报错提示
                } else {  // 如果现有行业已满, 则报错返回, 要求公众号管理员查看
                    $code = 1;
                    $msg  = '模板消息不在行业内, 请联系公众号管理员处理';
                    break;
//                    Output::instance()->resultCode(1, '模板消息不在行业内, 请联系公众号管理员处理');
//                    exit();
                }
            }

            /** 2.2 模板消息数量(25条)判断 */
            // 获得已设置的模板消息信息
            $templates  = TemplateMessage::getAllPrivateTemplate($user_cid);
            $templates  = $templates->template_list;
            $templates_count  = count($templates);

            if ($templates_count < template_message_max_num) {  // 如果已设置的模板消息数量 < 允许数量, 则进行添加操作
                // 先公众号添加模板消息
                $templateInfo = TemplateMessage::apiAddTemplate($user_cid, $moduleTemplate['tmNo']);

                $add_template = null;   // 用于记录添加进公众号的模板消息的信息(template_id, title, content, ...)

                if ($templateInfo->errcode == 0) {    // 模板消息加入公众号成功

                    // 再获得加入新模板消息后的所有已设置的模板消息
                    $templates_add  = TemplateMessage::getAllPrivateTemplate($user_cid);
                    $templates_add = $templates_add->template_list; // 这么写是因为微信返回的是一个对象, template_list里才是我们要的数组
                    // 遍历现有模板消息, 找到刚新增的模板消息
                    foreach ($templates_add as $templates_add_index => $template_add) {
                        if ($template_add->template_id == $templateInfo->template_id) { // 根据新增的模板消息的template_id来查找
                            $add_template = $template_add;  // 此时$add_template值是新的该条模板
                            break;
                        }
                    }

                    /**
                     * 遍历插入新模板消息之前的模板消息列表, 判断是否添加重复
                     * 根据content做字符串比较来判断是否重复
                     *      如果重复, 则删掉刚刚新增的模板消息, 并把已存在的模板消息作为新增信息($add_template = $template;)
                     */
                    foreach ($templates as $templates_index => $template) {
                        if (strcmp($add_template->content, $template->content) == 0) {  // 根据content判断是否重复
                            // 如果重复了, 则这个旧的模板消息被当做是新增的(用它的信息(template_id, title, content, ...))
                            $add_template = $template;  // 此时$add_template值是旧的该条模板

                            // 删除真实刚刚新增的模板消息
                            $delTemplate_result = TemplateMessage::delPrivateTemplate($user_cid, $templateInfo->template_id);
                            if ($delTemplate_result->errcode != 0) {    // 删除重复添加的模板消息失败
                                $subMsg = '删除重复添加的模板消息失败';
//                                Output::instance()->resultCode(1, '删除重复添加的模板消息失败'); // 只给页面抛错, 但并不终止程序
                                \Log::write('删除重复添加的模板消息失败' . json_encode($templateInfo));
                            }
                            break;
                        }
                    }
                } else {    // 模板消息添加失败(可能是公众号为授权)
                    $code = 1;
                    $msg  = '模板消息添加失败(可能是公众号为授权)';
                    break;
//                    Output::instance()->resultCode(1, '模板消息添加失败(可能是公众号为授权)');
//                    exit();
                }

                // 无论模板消息插入情况如何, 都把该type类型的模板加入到这个$user_cid的模板消息数据表中, 以便后期开启
                $data = [
                    'templateId'       => $add_template->template_id,
                    'name'              => $add_template->title,
                    'templateContent'   => $add_template->content
                ];

                $where['status'] = array('eq', $moduleTemplate['type']);
                $status_count = M()->table('wx_' . $user_cid . '_template_messages')->where($where)->count();

                // todo: 看数据表结构设计template_id是不允许为空的, 这里可能会报错
                if ($status_count > 0) {    // 如果这个status(type)的模板信息已存在, 则更新(如果是用户操作配置的话, 由于模板已存在, 只是template_id为NULL, 则一定是更新)
                    $result = M()->table('wx_' . $user_cid . '_template_messages')->where($where)->save($data);
                } else {    // 如果这个公众号中尚无该模板信息, 则新增(只有超管为用户开通模块是可能是新增)
                    $data['status'] = $moduleTemplate['type'];
                    $result = M()->table('wx_' . $user_cid . '_template_messages')->add($data);
                }
                if (!$result) { // 数据库修改时处错误
                    \Log::write('模板消息配置_修改本地数据库时错误_' . M()->getLastSql());
                    $subMsg .= '数据库修改时错误, 请联系管理员';
                }

            } else {
                $code = 1;
                $msg  = '模板消息数量已满, 请联系公众号管理员处理';
                break;
//                Output::instance()->resultCode(1, '模板消息数量已满, 请联系公众号管理员处理');
//                exit();
            }
        }

        $add_result = [
            'code'  => $code,
            'msg'   => $msg,
            'subMsg'=> $subMsg
        ];
        return $add_result;
//        Output::instance()->resultCode($code, $msg . $subMsg);
//        exit();
    }

    /**
     * 与微信公众平台配置相管理处理,删除模板消息
     * 重点是这个模块的模板消息, 其他模块是否存在共用
     *
     * @param array $moduleTemplateInfo 需要配置的模板包含的模板信息
     * @param int   $user_cid           为哪个用户配置
     */
    protected function delTemplate($moduleTemplateInfo, $user_cid)
    {
        $code = 0;
        $msg  = (count($moduleTemplateInfo) > 0) ? '模板消息删除成功' : '没有待删除的模板'; // '没有待删除的模板' 这几个汉字在前端js里用作匹配, 不可随意更改, 需要改写要一致
        $subMsg = '';
        // 遍历要删除的模板消息
        foreach ($moduleTemplateInfo as $moduleTemplate_index => $moduleTemplate) {

            // 使用了该条模板消息的所有module信息
            $moduleTemplateInfoWhere['type'] = array('eq', $moduleTemplate['type']);
            $moduleTemplateInfos = $this->moduleTemplateInfoModel->where($moduleTemplateInfoWhere)->select();

            if (count($moduleTemplateInfos) == 1) {    // 这个type类型的模板消息只有一个module用到, 那么现在关闭的就是这个module下的模板信息, 直接干掉平台和公众后台
                $forceDel_subMsg = $this->forceDelTemplate($user_cid, $moduleTemplate['type']);
                if (isset($forceDel_subMsg)) {
                    $subMsg .= $forceDel_subMsg;
                }

            } else {    // 这个type类型的模板消息有多个module用到, 不能直接关闭
                // 把所有使用到该模板的module放到一个数组里
                $arr_modules = [];
                foreach ($moduleTemplateInfos as $moduleTemplates_index => $moduleTemplates) {
                    array_push($arr_modules, $moduleTemplates['module']);
                }

                // 这个用户下, 使用了该模板的module的开启情况
                $customerModuleWhere = [
                    'customerId'    => $user_cid,
                    'group'         => array('in', $arr_modules),
                    'permission'    => 'allow'
                ];
                $customerModuleCount = $this->customerModuleModel->where($customerModuleWhere)->count();

                if ($customerModuleCount <= 1) {   // 如果众多模块中 <= 1个开启权限, 那关闭的就是这个module的模板, 直接关闭
                    $forceDel_subMsg = $this->forceDelTemplate($user_cid, $moduleTemplate['type']);
                    if (isset($forceDel_subMsg)) {
                        $subMsg .= $forceDel_subMsg;
                    }

                } else {    // 众多模块中, 使用该模板的module, 有多个开启权限, 不能关闭
                    \Log::write('模板消息存在共用_type=' . $moduleTemplate['type']);
                    $code = 1;
                    $msg  = '模板消息存在共用, 请联系管理员删除';
                    break;
//                    Output::instance()->resultCode(1, '模板消息存在共用, 请联系管理员删除');
                    // todo: 是否要强制删除提醒
//                    exit();
                }
            }
        }

        $del_result = [
            'code'  => $code,
            'msg'   => $msg,
            'subMsg'=> $subMsg
        ];
        return $del_result;
//        Output::instance()->resultCode($code, $msg . $subMsg);
//        exit();
    }

    /**
     * 执行删除模板信息操作
     *
     * @param $user_cid
     * @param $type
     *
     * @return mixed(null|string)   返回执行过程中遇到的错误信息
     */
    protected function forceDelTemplate($user_cid, $type)
    {
        $subMsg = null;

        // 根据type(status)去wx_3_template_message里查询要删除的模板的id
        $templateMessageWhere = ['status' => $type];
        $del_templateId = M()->table('wx_' . $user_cid . '_template_messages')->where($templateMessageWhere)->getField('templateId');

        // 删除平台的模板信息, 只是把templateId置空
        $result = M()->table('wx_' . $user_cid . '_template_messages')->where($templateMessageWhere)->save(['templateId' => '']);
        if (!$result) { // 平台模板信息删除失败
            \Log::write('平台模板信息删除失败' . M()->table('wx_' . $user_cid . '_template_messages')->getLastSql());
//            Output::instance()->resultCode(1, '平台模板信息删除失败'); // 只给页面抛错, 但并不终止程序
            $subMsg = '平台模板信息删除失败';
        }

        // 删除公众后台的模板信息
        $delTemplate_result = TemplateMessage::delPrivateTemplate($user_cid, $del_templateId);
        if ($delTemplate_result->errcode != 0) {    // 公众号删除模板消息失败
            \Log::write('公众号删除模板消息失败' . 'user_cid = ' . $user_cid . 'type = ' . $type);
//            Output::instance()->resultCode(1, '公众号删除模板消息失败'); // 只给页面抛错, 但并不终止程序
            $subMsg = '公众号删除模板消息失败';
        }

        return $subMsg;
    }

}
